﻿<html xmlns:MSHelp="http://msdn.microsoft.com/mshelp" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xanx="http://schemas.microsoft.com/developer/xanx/2005"><head><META http-equiv="Content-Type" content="text/html; charset=utf-8"><META NAME="save" CONTENT="history"><title>Sprite Sheet Sample</title>
<style><!--
/***********************************************************
 *             SCRIPT-SUPPORTING STYLES
 ***********************************************************/

/* Defines the userData cache persistence mechanism. */
.userDataStyle
{
	behavior: url(#default#userData);
}

/* Used to save the scroll bar position when navigating away from a page. */
div.saveHistory
{
	behavior: url(#default#saveHistory);
}

/* Formats the expand/collapse images for all collapsible regions. */
img.toggle
{
	border: 0;
	margin-right: 5;
}

/* Formats the Language filter drop-down image. */
img#languageFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Members Options filter drop-down image. */
img#membersOptionsFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Collapse All/Expand All images. */
img#toggleAllImage
{
	margin-left: 0;
	vertical-align: middle;
}

/* Supports XLinks */
MSHelp\:link
{
 	text-decoration: underline;
	color: #0000ff; 
	hoverColor: #3366ff;
	filterString: ;
}


body
	{
	background:	#FFFFFF;
	color: #000000;
	font-family:	Verdana;
	font-size: medium;
	font-style: normal;
	font-weight: normal;
	margin-top:	0;
	margin-bottom:	0;
	margin-left:	0;
	margin-right:	0;
	width:	100%;
	/*font-size: 110%;*/
	}

div.section
	{
	margin-left: 15px;
	}

div.hxnx5
	{
	margin-left: 1.5em;
	}

/* Font for all headings */	
h1, h2, h3, h4, h5, h6
	{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	margin-top: 18;
	margin-bottom: 8; 
	font-weight: bold;
	}
h1
	{
	font-size: 130%;
	color: #003399;
	}
div#scrollyes h1 /* Changes font size for full-scrolling topic */
	{
	font-size: 150%;
	}
h2
	{
	font-size: 125%;
	}
h3
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h4
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h5
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h6
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}

ul p, ol p, dl p
	{
	margin-left: 0em;
	}

p
	{
	margin-top: .6em;
	margin-bottom: .6em;
	}
	
td p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

dd p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

.image
	{
	text-align: center;
	}

dl
	{
	margin-top: 0em; 
	margin-bottom: 1.3em;
	}

dd
	{
	margin-bottom: 0em;
	margin-left: 0;
	}

dl.glossary dd 
{
	margin-bottom: 0em;  
	margin-left: 1.5em; 
}

dt
	{
	margin-top: .6em;
	margin-bottom: 1;
	}

ul, ol
	{
	margin-top: 0.6em;
	margin-bottom: 0.6em; 	
	}
	
ol
	{
	margin-left: 2.5em; 
	
	}	
	
ul
	{
	list-style-type: disc; 
	margin-left: 1.9em; 
	}

li
	{
	margin-bottom: 0.4em;
	}

ul ol, ol ol
	{
	list-style-type: lower-alpha;
	}

pre
	{
	margin-top: .6em;
	margin-bottom: .6em; 
	}

pre
	{
	font: 105% Lucida, mono; 
	color: #000066;
	}

code
{
	font-family: Monospace, Courier New, Courier;
	font-size: 105%;
	color:	#000066;
}

table.userdata td 
	{
	background: #ffffff;
	background-color: #F5F5F5;
	border-color: #ffffff;
	border: none;
	}	
table.clsWarning
	{
	background: #ffffff;
	padding: 0px;
	margin: 0px;
	border: none;
	}
table.clsWarning td
	{
	padding: 0px;
	margin: 0px;
	background: #ffffff;
	vertical-align: middle;
	font-size: 70%;
	}

div#mainSection table
	{
	width: 98%;
	background: #ffffff;
	margin-top: 5px;
	margin-bottom: 5px;
	}

div#mainSection table th
	{ 
	padding: 5px 6px;
	background: #EFEFF7;
	text-align: left;
	font-size: 70%;
	vertical-align: bottom;
	border-bottom: 1px solid #C8CDDE;
	}
div#mainSection table td
	{ 
	padding: 5px 5px;
	background: #F7F7FF;
	vertical-align: top;
	font-size: 70%;
	border-bottom: 1px solid #D5D5D3;
	}

div#syntaxCodeBlocks table th
	{
	padding: 1px 6px;
	color: #000066;
	}

div#syntaxCodeBlocks table td
	{
	padding: 1px 5px;
	}

/* Applies to the running header text in the first row of the upper table in the
   non-scrolling header region. */
span#runningHeaderText
{
	color: #003399;
	font-size: 90%;
	padding-left: 13;
}

/* Applies to the topic title in the second row of the upper table in the
   non-scrolling header region. */
span#nsrTitle
{
	color: #003399;
	font-size: 120%;
	font-weight: 600;
	padding-left: 13;
}

/* Applies to everything below the non-scrolling header region. */
div#mainSection
{
	font-size: 70%;
	width: 100%;
}

/* Applies to everything below the non-scrolling header region, minus the footer. */
div#mainBody
{
	font-size: 90%;
	margin-left: 15;
	margin-top: 10;
	padding-bottom: 20;
}

/* Adds right padding for all blocks in mainBody */
div#mainBody p, div#mainBody ol, div#mainBody ul, div#mainBody dl
{
	padding-right: 5;
}

div#mainBody div.alert, div#mainBody div.code, div#mainBody div.tableSection
{
	width:98.9%;
}

div.alert p, div.code p
{
	margin-top:5;
	margin-bottom:8;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
div#mainSection div.alert table
{
	border: 0;
}

div#mainSection div.alert table th
{
	padding-top: 0;
	padding-bottom: 0;
	padding-left: 5;
	padding-right: 5;
}

div#mainSection div.alert table td
{
	padding-left: 5;
	padding-right: 5;
}

img.note
{
	border: 0;
	margin-left: 0;
	margin-right: 3;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - End Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Non-scrolling Header Region Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Applies to the entire non-scrolling header region. */
div#header
{
	background-color: #D4DFFF;
	padding-top:	0;
	padding-bottom:	0;
	padding-left:	0;
	padding-right:	0;
	width:	100%;
}

/* Applies to both tables in the non-scrolling header region. */
div#header table
{
	margin-top:	0;
	margin-bottom: 0;
	border-bottom-color: #C8CDDE;
	border-bottom-style: solid;
	border-bottom-width: 1;
	background: #D4DFFF;
	width:	100%;
}

/* Applies to cells in both tables in the non-scrolling header region. */
div#header table td
{
	color: #0000FF;
	font-size: 70%;
	padding-right: 20;
	padding-top: 1;
	padding-bottom: 1;
	border: none;
	background: #D4DFFF;
}

/* Applies to the last row in the upper table of the non-scrolling header region. Text 
   in this row includes See Also, Constructors, Methods, and Properties. */
div#header table tr#headerTableRow3 td
{
	padding-bottom: 2;
	padding-top: 5;
	padding-left: 15;
}

/* Applies to the lower table in the non-scrolling header region. Text in this table
   includes Collapse All/Expand All, Language Filter, and Members Options. */
div#header table#bottomTable
{
	border-top-color: #FFFFFF;
	border-top-style: solid;
	border-top-width: 1;
	text-align: left;
	padding-left: 15;
}


blockquote
	{
	margin-left: 3.8em;
	margin-right: 3.8em;
	margin-top: .6em;
	margin-bottom: .6em;
	}

sup
	{
	text-decoration: none;
	font-size: smaller; 
	}

a:link
	{
	color: #0000FF;
/*    font-weight: bold */
	}
	
a:visited
	{
	color: #0000AA;
/*    font-weight: bold	*/
	}
	
a:hover
	{
	color: #3366FF;
/*    font-weight: bold */
	}
	
.label
	{
	font-weight: bold; 
	margin-top: 1em;
	margin-left: -26px;
	}
	
.tl
	{
	margin-bottom: .75em; 
	}
	
.atl
	{
	padding-left: 1.5em;
	padding-bottom: .75em; 
	}
	
.cfe
	{
	font-weight: bold; 
	}
	
.mini
	{
	font-size: smaller;
	}
	
.dt
	{
	margin-bottom: -.6em; 
	}
	
.indent
	{
	margin-left: 1.9em; 
	margin-right: 1.9em;
	}

.product
	{
	text-align: right;
	color: #333333;
	font-size: smaller;
	font-style: italic;
	}

.buttonbarshade
	{
	position: relative;
	margin: 0;
	left: 0px;
	top: 2;
	width: 50%;
	height: 40px;
	}

.buttonbartable
	{
	position: absolute;
	margin: 0;
	padding:0;
	border:0;
	left:0px;
	top: 2;
	width: 100%;
	height: 40px;
	}

/* background color, font for header */ 
table.buttonbartable td, table.buttonbarshade td
	{
	background: #ffffff; /*#5177B8; #80C615;*/
	border-left: 0px solid #80C615;
	margin: 0;
	padding: 0px 0px 0px 0px;
	font-family: Impact, sans-serif;
	font-size: 14pt;
	}

table.buttonbartable td.button1
	{
	background: #5177B8; /*#80C615;*/;
	padding: 0;
	font-weight: bold;
	text-align: center;
	cursor: hand;
	}

table.buttonbartable td.button2
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.button3
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.runninghead
	{
	padding-left: 0px;
	font-style: italic;
	text-align: left;
	}

.version
	{
	text-align: left;
	color: #000000;
	margin-top: 3em;
	margin-left: -26px;
	font-size: smaller;
	font-style: italic;
	}

.lang, .ilang
	{
	color: #0000ff;
	font: normal 7pt Arial, Helvetica, sans-serif;
	}

div.langMenu
	{
	position: absolute;
	z-index: 1;
	width: 96pt;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.langMenu ul
	{
	padding-left: 2em;
	margin-left: 0;
	}

div.filtered
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: 2px solid #aaaacc;
	background: #ffffff;
	}

div.filtered2
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: none;
	background: #ffffff;
	}

div.filtered h1, div.filtered h2, div.filtered h3, div.filtered h4
	{
	margin-left: -22px;
	}

div.filtered span.lang
	{
	position: relative;
	left: -22px;
	}

div.reftip
	{
	position: absolute;
	z-index: 1;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

a.synParam
	{
	color: #0000FF;
	/*color: #3F7800;*/ 	
	/*color: #8DC54F;*/
	text-decoration: none;
    font-weight: normal;
	}

a.synParam:hover
	{
	text-decoration: underline;
    font-weight: normal;
	}

div.sapop
	{
	position: absolute;
	z-index: 1;
	left: 26px;
	width: 100%;
	padding: 10px 10px 10px 36px;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.footer
	{
	width: 100%;
	border: none;
	background: #ffffff;
	margin-top: 18pt;
	padding-bottom: 12pt;
	color: #0000FF;
	/*color: #228B22; */
	text-align: center;
	font-size: 76%;
	}

div.preliminary
	{
	margin-top: 8pt;
	padding-bottom: 12pt;
	color: #A0A0A0;
	}

/* A procedure section. eg. 'To create a file', 'To add a value' */
div.proc
    {
	margin-left: 0.5em; 
    }
     
/* The title of a 'procedure' section. */
div.proc h3
    {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-weight: bold;
	font-size: 115%;
	margin-top: 1em;
	margin-bottom: 0.4em;
	margin-left: -0.5em; 
	color: #003399;
    }

div.proc ul
    {
    margin-left: 1.5em;
    }

div.proc ol
    {
    margin-left: 2.0em;
    }
      
.note
	{
	margin-left: 14pt;
	margin-right: 12pt;
	}

.indent1
	{
	margin-left: 12pt;
	}

.indent2
	{
	margin-left: 24pt;
	}

.indent3
	{
	margin-left: 36pt;
	}

p.proch
	{
	padding-left: 16px;
	}

p.proch img
	{
	position: relative; 
	vertical-align: top;
	left: -18px; 
	margin-right: -14px; 
	margin-bottom: -18px;
	}
	
div.clsPlatSpec
{
	background-color:#FFF8DC;
	border-style:solid;
	border-width:1pt 0pt 0pt 1pt;
	border-color:#ffE4C4;
	margin-top:0.6em;
	width:100%;
}


/* Applies to the language labels in the Language Filter drop-down list. */
.languageFilter
{
	color:	#0000FF;
	cursor:hand;
	text-decoration:underline;
	padding-bottom:4;
}

/* Dropdown areas */

#languageSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}

#membersOptionsSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}
--></style>

<xml>
<MSHelp:TOCTitle Title="Sprite Sheet Sample" />
<MSHelp:RLTitle Title="Sprite Sheet Sample" />
<MSHelp:Keyword Index="A" Term="O:Microsoft.Xna.SpriteSheet" />
<MSHelp:Keyword Index="A" Term="3d1d46c0-ccf3-7096-5775-cccc9a4ee950" />
<MSHelp:Keyword Index="K" Term="Sprite Sheet Sample" />
<MSHelp:Attr Name="ProjType" Value="LocalProj" />
<MSHelp:Attr Name="ProjType" Value="XNA_20" />
<MSHelp:Attr Name="DocSet" Value="XNA" />
<MSHelp:Attr Name="DocSet" Value="ExpressLibVS" />
<MSHelp:Attr Name="DocSet" Value="C#" />
<MSHelp:Attr Name="Locale" Value="en-us" />
<MSHelp:Attr Name="AssetID" Value="3d1d46c0-ccf3-7096-5775-cccc9a4ee950" />
<MSHelp:Attr Name="TopicType" Value="kbOrient" />
</xml>
</head><body><div id="mainSection"><div id="mainBody">

  <h1>Sprite Sheet Sample</h1>

  This sample shows how to implement sprite sheets, combining many separate sprite images into a single larger texture that will be more efficient for the graphics card.

  <a name="ID2EK"></a><h1 class="heading">Sample Overview</h1><div id="ID2EK" class="hxnx1">
    

    <p>Graphics cards are slow to get going, but then extremely fast after they get started. If you ask the graphics card to draw one single triangle, it will take a relatively long time for it to wake up and notice your request, but then it will draw the triangle in hardly any time at all. If you ask it to draw 100 triangles, it will take exactly the same amount of time to get going, and then draw all 100 triangles in not much longer time than it took for just one. To get the best performance, you want to give the graphics card large batches of triangles rather than feeding them to it one at a time.</p>

    <p>The <b>SpriteBatch</b> class in the XNA Framework does exactly this. If you draw more than one sprite in a row using the same texture, it will batch them up, then give them all to the graphics card in one event. This works only when the sprites use the same texture, however. If you draw two sprites using texture A, then two using texture B, <b>SpriteBatch</b> will say, "Hey graphics card, here are two sprites. Now stop, change your texture. OK, now here are two more sprites." It would be faster if it could give all four sprites to the graphics card in a single batch, but it cannot do this because the texture is not the same.</p>

    <p>What if you made a single bigger texture that contained the image from texture A and also the image from texture B, arranged next to each other? You could then use the overload of <b>SpriteBatch.Draw</b> that lets you specify a source rectangle parameter, telling the card which part of this bigger texture to display on the screen. The results will look the same as before, but now all four sprites use the same texture, so <b>SpriteBatch</b> can render them more efficiently.</p>

    <p>Manually combining sprite images into larger sheets works well if you have just a few sprites, but it quickly becomes a burden as your game grows larger. When you have hundreds of sprites, it can be laborious having to manually pack them all into a single sprite sheet texture, and then remember where you put each image so you know what source rectangle to pass to <b>SpriteBatch.Draw</b> in your game code.</p>

    <p>This sample automates the process of creating sprite sheets by using a custom content processor. You provide an XML file listing any number of individual bitmap files, one per sprite. The processor reads all these bitmaps, packs them into a single larger texture, and saves this new texture along with information recording what source rectangle should be used for each sprite. You can then look up your sprites by name rather than having to remember the specific coordinates for each image.</p>

    <a name="ID2EFB"></a><h2 class="subHeading">Minimum Shader Profile</h2><div id="ID2EFB" class="hxnx2">
      
      <dl class="glossary">
        <dt>Vertex Shader Model 1.1</dt>
        <dt>Pixel Shader Model 1.1</dt>
      </dl>
    </div>

    <a name="ID2ERB"></a><h2 class="subHeading">Sample Controls</h2><div id="ID2ERB" class="hxnx2">
      
      <p>This sample uses the following keyboard and gamepad controls.</p>

      <table>
        <tr>
          <th>Action</th>
          <th>Keyboard Control</th>
          <th>Gamepad Control</th>
        </tr>
        <tr>
          <td>Exit the sample.</td>
          <td>ESC or ALT+F4</td>
          <td>
            <b>BACK</b>
          </td>
        </tr>
      </table>
    </div>
  </div>

  <a name="ID2ERC"></a><h1 class="heading">How the Sample Works</h1><div id="ID2ERC" class="hxnx1">
    

    <p>Sprite sheets are created from XML files that list any number of individual sprite bitmaps, for instance:</p>

    <pre>
    &lt;XnaContent&gt;
      &lt;Asset Type="System.String[]"&gt;
        &lt;Item&gt;cat.tga&lt;/Item&gt;
        &lt;Item&gt;glow1.png&lt;/Item&gt;
        &lt;Item&gt;glow2.png&lt;/Item&gt;
      &lt;/Asset&gt;
    &lt;/XnaContent&gt;  </pre>

    <p>To create a new sprite sheet, add an XML file in this format to your Content folder. Make sure the Content Importer property is set to <b>XML Content - XNA Framework</b>, and change the Content Processor setting to <b>SpriteSheetProcessor</b>. This will build all the sprite bitmaps listed in your XML file into a sprite sheet .xnb file, which you can load into your game by calling <b>Content.Load&lt;SpriteSheet&gt;(...)</b>.</p>

    <p>See the <b>SpriteSheetGame.Draw</b> method for an example of how to use the <b>SpriteSheet</b> object. You can look up individual sprites either by name (as used for the cat) or by index (as used for the glow animation). You can perform math on the index values to cycle through multiframe sprite animations.</p>

    <p>To reuse this code in your own game, add the <b>SpriteSheetPipeline</b> and <b>SpriteSheetRuntime</b> projects to your solution.</p>
    <div class="proc"><h3 class="subHeading">To make the pipeline project available for building your content</h3><div class="subSection">
      

      <ol>
        <li>Right-click the <b>Content | References</b> item in your content project.</li>
        <li>Click <b>Add Reference</b>.</li>
        <li>Click the <b>Projects</b> tab, and select the SpriteSheetPipeline project.</li>
      </ol>
    </div></div>
      <p>Finally, you must add a reference to make the <b>SpriteSheet</b> class available to your game code.</p>
      <div class="proc"><h3 class="subHeading">To add a reference</h3><div class="subSection">
        
        <ol>
          <li>Right-click the <b>References</b> item in your main game project.</li>
          <li>Click <b>Add Reference</b>.</li>
          <li>Click the <b>Projects</b> tab, and select the SpriteSheetRuntime project</li>
        </ol>
      </div></div>
      <a name="ID2ERG"></a><h2 class="subHeading">The SpriteSheetProcessor</h2><div id="ID2ERG" class="hxnx2">
        

        <p>The <b>SpriteSheetProcessor</b> class runs during the content build process. It is responsible for converting an array of strings that contain texture file names into a <b>SpriteSheetContent</b> object. The <b>SpriteSheetWriter</b> class then writes this <b>SpriteSheetContent</b> data into a binary .xnb file. At run time, the <b>SpriteSheetReader</b> class reads the .xnb data back into a <b>SpriteSheet</b> object that can be used by your game.</p>

        <p>See <a href="http://msdn2.microsoft.com/en-us/library/bb447756.aspx">http://msdn2.microsoft.com/en-us/library/bb447756.aspx</a> for more information about the architecture of the Content Pipeline.</p>

        <p>The hard work of this processor is implemented by the <b>SpritePacker</b> helper class. This class arranges many small sprite bitmaps onto a single larger sheet. The algorithm works as follows:</p>

        <ol>
          <li>Sort sprites by size, so the biggest ones will be arranged first. If you leave the smaller sprites until the end, it makes it more likely they could fit into holes left between earlier big ones.</li>
          <li>
            <p>Call <b>PositionSprite</b> for each sprite in turn, so you can decide where to put each one. This starts at the top left of the sheet, and checks whether it overlaps with any previously arranged sprite, as follows:</p>
            <ul>
              <li>If there is a collision, move to the right, looking for a free space.</li>
              <li>If it reaches the right edge of the sheet, wrap back to the left, and move down one row.</li>
              <li>Repeat until a free location is found.</li>
            </ul>
          </li>
        </ol>

        <p>When the packing process is complete, the processor calls <b>ContentBuildLogger.LogImportantMessage</b>, which reports how big a sheet it created and what percentage of this sheet contains sprite data versus unused space. Visual Studio displays this information in the output pane after building the content. Keep in mind that it is often impossible to find a perfect fit, so there will usually be some wasted space.</p>

      </div>

      <a name="ID2EMAAC"></a><h2 class="subHeading">Texture Filtering</h2><div id="ID2EMAAC" class="hxnx2">
        

        <p>When you use sprite sheets, pixels from the edge of one sprite may bleed onto others. This often happens when you are scaling or rotating the sprites. This occurs because the graphics card applies filtering, averaging out the values of adjacent pixels to reduce aliasing. If one sprite is arranged next to another of a radically different color, this filtering may accidentally pick up some amount of that other color, which will cause a nasty looking border along the edge of your sprite.</p>

        <p>The sprite sheet processor presented in this sample automatically avoids filtering problems by including one pixel of padding around the edge of each sprite while they are being arranged onto the sheet. The <b>SpritePacker.CopySpritesToOutput</b> method fills this border area with a copy of the colors from the edge of the sprite. Things will look acceptable even if the graphics card filters values from slightly outside the sprite itself.</p>
      </div>

    </div>

  <a name="ID2EZAAC"></a><h1 class="heading">Extending the Sample</h1><div id="ID2EZAAC" class="hxnx1">
    

    <p>This sample always outputs the sprite sheet in 32-bit <b>Color</b> format. To save space, you could change the <b>SpriteSheetProcessor</b> to convert the bitmap data into some other format, perhaps using DXT1 or DXT5 compression. You could even use a content processor parameter to make the compression optional for each sprite sheet.</p>

    <p>To create a processor parameter, add the following property to the <b>SpriteSheetProcessor</b> class.</p>

    <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>
    [DefaultValue(false)]
    public bool Compress
    {
        get { return compress; }
        set { compress = value; }
    }

    bool compress;    </pre></pre></td></tr></table></span></div>

    <p>To implement the compression, add the following code at the end of <b>SpriteSheetProcessor.Process</b>, immediately before the return statement.</p>

    <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>
    if (compress)
    {
        spriteSheet.Texture.ConvertBitmapType(typeof(Dxt5BitmapContent));
    }    </pre></pre></td></tr></table></span></div>

    <p>DXT compression requires texture sizes to be multiples of four. We need to make sure the generated sprite sheet will always be a valid size. The packing algorithm always produces sheets with a valid width. However, the height could be anything, so we must round it up to the next larger multiple of four. Add this line to <b>SpritePacker.PackSprites</b> immediately before the "Sort the sprites back into index order" comment:</p>

    <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>
    outputHeight = (outputHeight + 3) &amp; ~3;
    </pre></pre></td></tr></table></span></div>

    <p>After rebuilding the processor project, you can select any XML content file that is set to use the sprite sheet processor. Then open up the Visual Studio properties pane, expand the <b>+</b> sign next to the <b>Content Processor</b> property, and change the newly created <b>Compress</b> setting.</p>

  </div>

</div><div class="footer" id="footer"><p>© 2008 Microsoft Corporation. All rights reserved.<br>Send feedback to <a href="mailto:xnags@microsoft.com?subject=Documentation Feedback: Sprite Sheet Sample">xnags@microsoft.com</a>.</p></div></div></body></html>